﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Plat.WfProcess.Common;
using Plat.WfProcess.Utility;
using Plat.WfProcess.DataModel;
using Plat.WfProcess.Business;

namespace Plat.WfProcess.Business
{
    internal class ProcessInstanceManager
    {
        #region ProcessInstanceManager 属性
        private ProcessInstanceRepository _processInstanceRepository;

        private ProcessInstanceRepository processInstanceRepository
        {
            get
            {
                if (_processInstanceRepository == null)
                {
                    _processInstanceRepository = new ProcessInstanceRepository();
                }
                return _processInstanceRepository;
            }
        }

        internal long ApplicationInstanceID
        {
            get;
            set;
        }

        internal string ProcessInstanceGUID
        {
            get;
            set;
        }

        internal string ProcessGUID
        {
            get;
            set;
        }
        #endregion

        #region ProcessInstance 构造函数
        /// <summary>
        /// 启动流程时候的构造函数
        /// </summary>
        /// <param name="applicationInstanceID"></param>
        /// <param name="processEntity"></param>
        internal ProcessInstanceManager(long applicationInstanceID,
            string processGUID)
        {
            ApplicationInstanceID = applicationInstanceID;
            ProcessGUID = processGUID;
        }

        /// <summary>
        /// 流程已经运行的构造函数
        /// </summary>
        /// <param name="processInstanceGUID"></param>
        internal ProcessInstanceManager(string processInstanceGUID)
        {
            ProcessInstanceGUID = processInstanceGUID;
        }
        #endregion

        #region ProcessInstanceManager 基本数据操作
        internal ProcessInstanceEntity Select(string processInstanceGUID)
        {
            return processInstanceRepository.SelectById(processInstanceGUID);
        }

        internal IList<ProcessInstanceEntity> SelectRunningProcess(long applicationInstanceID,
            string processGUID)
        {
            return processInstanceRepository.Select("ApplicationInstanceID == @0 and ProcessGUID.ToString() == @1 and State == @2",
                applicationInstanceID,
                processGUID,
                (short)ProcessStateEnum.Running);
        }

        internal IList<ProcessInstanceEntity> Select(int pageIndex,
            int pageSize,
            out long allRowsCount,
            long applicationInstanceID,
            string processGUID)
        {
            return processInstanceRepository.Select(pageIndex, 
                pageSize,
                out allRowsCount, 
                string.Empty,
                false,
                "CreatedDateTime",
                "ApplicationInstanceID == @0 and ProcessGUID.ToString() == @1",
                applicationInstanceID,
                processGUID);
        }

        /// <summary>
        /// 流程实体插入
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        internal string Insert(ProcessInstanceEntity entity)
        {
            return Insert(entity, null);
        }

        /// <summary>
        /// 流程数据插入
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="wfLinqDataContext"></param>
        /// <returns></returns>
        internal string Insert(ProcessInstanceEntity entity, ProcessModelDataContext wfLinqDataContext)
        {
            if (wfLinqDataContext != null)
            {
                processInstanceRepository.LinqDataContext = wfLinqDataContext;
            }
            return processInstanceRepository.Insert(entity).ProcessInstanceGUID.ToString();
        }

        /// <summary>
        /// 流程实例更新
        /// </summary>
        /// <param name="entity"></param>
        internal void Update(ProcessInstanceEntity entity)
        {
            Update(entity, null);
        }

        /// <summary>
        /// 流程实例更新
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="wfLinqDataContext"></param>
        internal void Update(ProcessInstanceEntity entity, 
            ProcessModelDataContext wfLinqDataContext)
        {
            if (wfLinqDataContext != null)
            {
                processInstanceRepository.LinqDataContext = wfLinqDataContext;
            }
            processInstanceRepository.Update(entity);
        }

        internal void Delete(string processInstanceGUID, 
            ProcessModelDataContext wfLinqDataContext)
        {
            if (wfLinqDataContext != null)
            {
                processInstanceRepository.LinqDataContext = wfLinqDataContext;
            }
            processInstanceRepository.Delete(processInstanceGUID);
        }

        /// <summary>
        /// 根据流程定义，创建新的流程实例
        /// </summary>
        /// <param name="processID">流程定义ID</param>
        /// <returns>流程实例的ID</returns>
        internal ProcessInstanceEntity CreateNewProcessInstanceObject(ProcessEntity processEntity)
        {
            ProcessInstanceEntity entity = new ProcessInstanceEntity();
            entity.ProcessGUID = processEntity.ProcessGUID;
            entity.ProcessInstanceGUID = Guid.NewGuid().ToString();
            entity.ProcessName = processEntity.ProcessName;
            entity.ApplicationInstanceID = ApplicationInstanceID;
            entity.State = (int)ProcessStateEnum.Running;
            entity.CreatedDateTime = System.DateTime.Now;
            entity.LastUpdatedDateTime = System.DateTime.Now;
            
            return entity;
        }
        #endregion

        #region 流程业务规则处理
        /// <summary>
        /// 流程完成，设置流程的状态为完成
        /// </summary>
        /// <returns>是否成功</returns>
        internal void Complete(WfLogonUser executor)
        {
            Complete(executor, null);
        }

        /// <summary>
        /// 流程完成，设置流程的状态为完成
        /// </summary>
        /// <returns>是否成功</returns>
        internal void Complete(WfLogonUser currentUser,
            ProcessModelDataContext wfLinqDataContext)
        {
            ProcessInstanceEntity bEntity = Select(ProcessInstanceGUID);
            if (bEntity.State == (int)ProcessStateEnum.Running)
            {
                bEntity.State = (int)ProcessStateEnum.Complete;
                bEntity.IsProcessCompleted = 1;
                bEntity.EndedDateTime = System.DateTime.Now;
                bEntity.EndedByUserID = currentUser.UserID;
                bEntity.EndedByUserName = currentUser.UserName;

                Update(bEntity, wfLinqDataContext);
            }
            else
            {
                throw new ProcessInstanceException("流程不在运行状态，不能被完成！");
            }
        }

        /// <summary>
        /// 流程的取消操作
        /// </summary>
        /// <returns>是否成功</returns>
        internal bool Abort()
        {
            ProcessInstanceEntity entity = processInstanceRepository.SelectById(ProcessInstanceGUID);

            if (entity.State == (int)ProcessStateEnum.Running
                || entity.State == (int)ProcessStateEnum.Ready
                || entity.State == (int)ProcessStateEnum.Suspended)
            {
                processInstanceRepository.Abort(ProcessInstanceGUID);

                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程已经结束，或者已经被取消或终止！");
            }
        }

        /// <summary>
        /// 流程终止操作
        /// </summary>
        /// <returns></returns>
        internal bool Terminate()
        {
            ProcessInstanceEntity entity = processInstanceRepository.SelectById(ProcessInstanceGUID);

            if (entity.State == (int)ProcessStateEnum.Running
                || entity.State == (int)ProcessStateEnum.Ready
                || entity.State == (int)ProcessStateEnum.Suspended)
            {
                processInstanceRepository.Terminate(ProcessInstanceGUID);

                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程已经结束，或者已经被取消！");
            }
        }

        /// <summary>
        /// 删除不正常的流程实例（流程在取消状态，才可以进行删除！）
        /// </summary>
        /// <param name="processInstanceGUID"></param>
        /// <returns></returns>
        internal bool Delete(string processInstanceGUID)
        {
            ProcessInstanceEntity entity = processInstanceRepository.SelectById(ProcessInstanceGUID);

            if (entity.State == (int)ProcessStateEnum.Aborted)
            {
                processInstanceRepository.Delete(processInstanceGUID);
                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程只有先取消，才可以删除！");
            }
        }
        #endregion

    }
}
